#!/usr/bin/perl
#
# Twitim - A Twitter Client for GNOME
#

require v5.8;

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin";
use utf8;

use Gtk2 -init;
use Glib qw(TRUE FALSE);
use AnyEvent;
# use Data::Dumper;

use Twitim::XMPP;
use Twitim::Twitter;
use Twitim::NetBase;
use Twitim::L10N;
use Twitim::AutoStart;
use Twitim::Config;

use Twitim::MainWindow;
use Twitim::Preferences;
use Twitim::TrayIcon;
use Twitim::Notification;
use Twitim::SessionManager;
use Twitim::Twitim;

binmode( STDOUT, ':utf8' );

###########################################################################
# variables
#

our $VERSION  = '1.6';
our $APP_NAME = 'Twitim';
our $APP_URL  = 'http://code.google.com/p/twitim/';
our $HELP_URL = $APP_URL;
my $CFG_FILE = "$ENV{'HOME'}/.twitimrc";
our $DESKTOP_ENTRY_DIR = "$FindBin::Bin/etc/";
our $PIXMAPS_DIR       = "$FindBin::Bin/pixmaps/";
our $TWITTER_URL       = 'http://twitter.com/';
my $cache_dir = "/tmp/twitim-$ENV{'USER'}/";
my $lock_dir  = $cache_dir . "lockdir";

our $CFG = Twitim::Config->new($CFG_FILE);
my @Tw_All_Msg_Id;
our $APP_ICON;

# objects
our $TRAY_ICON;
our $AUTO_START;
our $TWITTER;
our $XMPP;
our $NOTIFY;
our $MAINWIN;
my  $SESSION;

if ( -e '/etc/twitim/twitim.conf' ) {
    require '/etc/twitim/twitim.conf';    ## no critic
}

###########################################################################
# main


unless ( -e $CFG_FILE ) {
    my $assistante;

    eval { use Twitim::Assistant; };

    $assistante = Twitim::Assistant->new(
        on_destroy => sub {
            my %auth = $assistante->get_data;
            $CFG->{'default'}->{'access_token'}  = $auth{'token'};
            $CFG->{'default'}->{'access_secret'} = $auth{'token_secret'};
            $CFG->{'default'}->{'twitter_user'}  = $auth{'user'};
            start();
        },
    );
    $assistante->start;
}
else {
    show_config_error_dialog() unless ( -r $CFG_FILE && -w $CFG_FILE );
    $CFG->read;
    start();
}

Gtk2->main;

sub start {

    # set global variables
    $APP_ICON                    = check_app_icon($CFG);
    $Twitim::Twitim::www_browser = $CFG->{'default'}->{'web-browser'}
        || "gnome-open";
    $CFG->{'default'}->{'system_font'} = 1
        unless defined $CFG->{'default'}->{'system_font'};
    $CFG->{'default'}->{'use_geometry'} = 1
        unless defined $CFG->{'default'}->{'use_geometry'};
    $CFG->{'default'}->{'show_user_icon'} = 1
        unless defined $CFG->{'default'}->{'show_user_icon'};
    $CFG->{'default'}->{'icon_size'} ||= 1.5;
    $CFG->{'default'}->{'font'}      ||= "Sans 12";

    Twitim::NetBase->set_my_id($CFG->{'default'}->{'xmpp_user'});
    Twitim::NetBase->set_my_id($CFG->{'default'}->{'twitter_user'});
    $Twitim::NetBase::L10N = \&l10n;

    # FIXME: set signal handling 
    $SESSION = Twitim::SessionManager->new;
    $SESSION->connect;
    check_processes();

    $SIG{'INT'} = $SIG{'TERM'} = $SIG{'KILL'} = $SIG{'HUP'}
        = sub { $MAINWIN->quit };
    $SIG{'CHLD'} = "IGNORE";

    # objects
    $NOTIFY     = Twitim::Notification->new;
    $MAINWIN    = Twitim::MainWindow->new($CFG);
    $TRAY_ICON  = Twitim::TrayIcon->new($MAINWIN);
    $AUTO_START = Twitim::AutoStart->new($DESKTOP_ENTRY_DIR);

    $XMPP = Twitim::XMPP->new(
        userid   => $CFG->{'default'}->{'xmpp_user'},
        password => $CFG->{'default'}->{'xmpp_pass'},

        cb => {
            connect => sub { 
                $MAINWIN->set_menu_sensitive( "Connect", 0 );
                $MAINWIN->set_menu_sensitive( "Twitter", 1 );
            },
            disconnect => sub { 
                $MAINWIN->set_menu_sensitive( "Connect", 1 ) if $XMPP->is_valid;
            },
            message        => \&check_message,
            error          => \&set_error_alert,
            session_status => sub {
                my $text = shift;
                $MAINWIN->set_status_line( 'XMPP session', $text );
            },
            get_current_tab => sub { $MAINWIN->get_current_tab_name() },
            get_opened_tab  => sub { $MAINWIN->get_opened_tabs() },
        }
    );

    $TWITTER = Twitim::Twitter->new(
        userid   => $CFG->{'default'}->{'twitter_user'},
        access_token  => $CFG->{'default'}->{'access_token'},
        access_secret => $CFG->{'default'}->{'access_secret'},
	
        delay    => $CFG->{'default'}->{'twitter_delay'},
        max_dm_id => $CFG->{'default'}->{'max_dm_id'},
        include_web_msg => $CFG->{'default'}->{'include_msg_from_web'},
        cb       => {
            message => \&check_message,
            error   => \&set_error_alert
        }
    );
    webapi_connect();
}

###########################################################################
# Twitter API

sub webapi_connect {
    my $update = shift;

    get_my_icon();
    $TWITTER->friends_timeline('Timeline') unless defined $update;
    $TWITTER->direct_messages('Timeline')  unless defined $update;
    $TWITTER->followers_ids                unless defined $update;
    $TWITTER->followers('all but Timeline');

    my $tablist = join( "|", grep !/Timeline/, $TWITTER->get_api_names );

    my $watchlist = $MAINWIN->get_active_watchlist;
    foreach my $tab ( grep /^$tablist$/, @$watchlist ) {
        my $api = $TWITTER->name2api($tab);
        $TWITTER->$api($tab);
    }

    if ( !defined $update ) {
        $TWITTER->set_access_timer('friends_timeline');
        $TWITTER->set_dm_timer('direct_messages');
    }
}

###########################################################################
# process signals
#

sub quit {
    my $session_disconnect = shift;
    # $SESSION->disconnect;
  
    if ( $TWITTER->get_max_message_id ) {
        $CFG->{'default'}->{'max_message_id'} = $TWITTER->get_max_message_id;
    }

    if ( Twitim::NetBase->get_my_icon_url ) {
        $CFG->{'default'}->{'my_icon'} = Twitim::NetBase->get_my_icon_url;
    }

    delete $CFG->{'default'}->{'twitter_pass'}; # removed obsolete password

    $CFG->write;
    $AUTO_START->end;

    undef $TRAY_ICON;    # avoid bothersome segmentation fault
    Gtk2->main_quit unless $session_disconnect;

    rmdir($lock_dir) if -e $lock_dir;
}

###########################################################################
# Misc

sub send_message {
    my ( $string, $reply_id ) = @_;

    if ( $XMPP->is_valid && !defined $XMPP->get_error && !$reply_id ) {
        $XMPP->update($string);
    }
    else {
        $TWITTER->update( $string, $reply_id );
    }
}

sub check_message {
    my ($arg_ref) = @_;

    my $id = $arg_ref->{'message_id'};
    my $output = $arg_ref->{'output'} || 'all';

    if ( defined $id ) {
        if ( grep /$id/, @Tw_All_Msg_Id ) {
            return if $output eq 'all' or $output eq 'Timeline';
        }
        else {
            push( @Tw_All_Msg_Id, $id );
            return if $output eq 'none';
        }
    }

    $MAINWIN->append_mesg( $arg_ref->{'user_id'}, $arg_ref->{'body'}, $id,
        $arg_ref->{'unixtime'}, $output, $arg_ref->{'rt'} );
}

sub get_my_icon {
    return unless exists $CFG->{'default'}->{'twitter_user'};

    my $jid = $CFG->{'default'}->{'twitter_user'};

    if ( exists $CFG->{'default'}->{'my_icon'} ) {
        Twitim::NetBase->set_icon( $jid, $CFG->{'default'}->{'my_icon'} );
        Twitim::NetBase->get_icon( $jid,
            $CFG->{'default'}->{'show_user_icon'} );
    }
    else {
        $TWITTER->show_user($jid);
    }
}

sub set_error_alert {
    my ( $desc, $text, $optional_desc ) = @_;

    # status line
    $text = sprintf l10n("%s Error: %s"), $desc, $text if defined $text;
    my $n = $optional_desc || $desc;
    $MAINWIN->set_status_line( $n, $text );

    # set menu sensitive
    if ( $desc eq 'XMPP' ) {
        my $state = $text ? FALSE : defined $optional_desc ? FALSE : TRUE;
        $MAINWIN->set_menu_sensitive( "Twitter", $state );
    }

    # menu icon
    my ( @each_error, $icon, $icon_text );

    foreach my $method ( $XMPP, $TWITTER ) {
        next if !defined $method || !defined $method->get_error;

        my $text = $method->get_error;
        my $desc = ( $method == $XMPP ) ? 'XMPP' : 'Twitter API';
        $text = sprintf( l10n("%s Error: %s"), $desc, $text );
        $text =~ s|^(.*?:)|<b>$1</b>|;
        push @each_error, $text;
    }

    if ( $#each_error != -1 ) {
        my $threshold = $XMPP->is_valid ? 0 : 1;
        $icon = $#each_error == $threshold ? "offline.png" : "busy.png";
        $icon_text = join( "\n\n", @each_error );
    }

    $MAINWIN->_set_menu_icon( $icon, $icon_text );
}

sub show_config_error_dialog {
    my $parent = shift;

    my $text1 = "Can not read/write the config file.";
    my $text2 = "Please check permission of the config file.";

    my $dialog = make_dialog( $text1, $text2, undef, 'error', 'ok' );
    exit;
}

sub check_processes {
    mkdir( $cache_dir, oct(700) ) unless ( -d $cache_dir );
    return if ( mkdir( $lock_dir, oct(700) ) );

    my $head = "Twitim is already running.";
    my $body
        = "If Twitim is no longer running, press the OK button for force starting Twitim.";
    my $response
        = make_dialog( $head, l10n($body), undef, 'warning', 'ok-cancel' );
    exit unless $response eq 'ok';
}

sub check_app_icon {
    my $cfg = shift;

    my $icon;
    my $system_icon = '/etc/twitim/twitim.png';
    my $custom_icon = $cfg->{'default'}->{'icon'};

    if ( check_image($system_icon) ) {
        $icon = $system_icon;
    }
    elsif ( defined $custom_icon ) {
        if ( check_image($custom_icon) ) {
            $icon = $custom_icon;
        }
        else {
            delete $cfg->{'default'}->{'icon'};
        }
    }

    return $icon;
}

sub check_image {
    my $image_file = shift;
    my $is_ok      = 0;

    unless ( -r $image_file ) {
        # print "$image_file is not found.\n";
        return $is_ok;
    }

    eval { my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file($image_file); };
    $is_ok = $@ ? 0 : 1;
    print "$image_file is not a image file.\n" unless $is_ok;

    return $is_ok;
}
